"""configure of parser"""

import configparser
import os
import pathlib

from exceptions import LoadConfError, NotRecognizeConfTypeError, ConfNotExitError, FieldNameError
from conf_types import ConfType, ConfUnit
from encoding import Encoding


class AbstractConf:
    """abstract conf class, define some data will be used later"""

    def __init__(self):
        # a Path obj
        self.log_file = None
        # if conf data show a dir, log_dir will not None
        self.log_dir = None
        # if conf data show a file, is_file will be True
        self.is_file = None
        # if log file so big, it will be use more cpu core to process
        self.use_mul_core = None
        # approximate average split big log file， here are some details you could see _judge_size method
        self.file_interval = None
        # log encoding
        self.log_file_encoding = None

    def conf_typeof(self, typeof):
        """
        select a conf loader according to typeof
        :param typeof:
        :return:
        """
        raise NotImplementedError


class FileConf(AbstractConf):

    def __init__(self, conf_path: str, limit_size=None, *, typeof=ConfType.ini, encoding=Encoding.UTF8):
        """
        only supply single conf file
        DONE -> _TODO if the file will so big, how can we deal with it? I think first set a limit size,
        if over the size will use
        TODO more cpu core, parallel handle log file, but there are so many trouble will to solve, let's try my best
        :param conf_path:
        """
        super().__init__()
        self.conf_type = typeof
        # TODO how to input
        self._limit_size = limit_size
        self.log_file_encoding = encoding

        self._load_conf(conf_path, typeof)
        self.use_mul_core, self.file_interval = self._decision_making()

    def _decision_making(self):
        """
        make decision of log file, get interval, whether use more cpu core,etc
        :return:
        """
        # need judge conf input is a single file or a dir
        # TODO but if not a file, it is so hard
        if self.is_file:
            if not (self.log_file.exists() and self.log_file.is_file()):
                print(self.log_file)
                raise LoadConfError

            # self.conf_file = self.log.open(encoding=self.log_file_encoding)
            return self._judge_size()

        else:
            # TODO later think dir
            pass

    def _judge_size(self):
        """
        this is core method to split a very big log file
        first according to log size approximate split cpu_count (based on Byte)
        The rest is in parser module, see details to parser.main._patch_file_point method
        :return:
        """
        file_size = os.stat(self.log_file).st_size / ConfUnit.B
        if file_size > self._limit_size:
            # can use multi cpu core
            # use multi cpu is easily, but data communicate data will so hard
            return True, file_size // os.cpu_count()
        return False, 1

    @property
    def encoding(self):
        """
        get current log file has set encoding
        :return:
        """
        return self.log_file_encoding

    @encoding.setter
    def encoding(self, encode):
        """
        change current log file encoding
        :param encode:
        :return:
        """
        self.log_file_encoding = encode

    def conf_typeof(self, typeof):
        """
        change conf type
        :param typeof:
        :return:
        """
        self.conf_type = typeof

    def _load_conf(self, conf_path, typeof):
        """
        according to conf type choose a conf loader
        :param conf_path:
        :param typeof:
        :return:
        """
        if typeof.lower() == "ini":
            self._ini_loader(conf_path)
        elif typeof.lower() == "json":
            self._json_loader(conf_path)
        elif typeof.lower() == "yaml":
            self._yaml_loader(conf_path)

        else:
            raise NotRecognizeConfTypeError

    def _ini_loader(self, conf_path):
        """
        ini loader
        :param conf_path:
        :return:
        """
        ini_parser = configparser.ConfigParser()
        ok = ini_parser.read(conf_path)
        print(ok, conf_path)
        if not ok:
            raise ConfNotExitError

        self.is_file = ini_parser.getboolean(ini_parser.default_section, "is_file")

        try:
            if self.is_file:
                # is file, mean only one log file
                self.log_file = pathlib.Path(ini_parser.get(ini_parser.default_section, "path"))

            else:
                # is a dir, mean have more log files
                self.log_dir = pathlib.Path(ini_parser.get(ini_parser.default_section, "dir"))
        except configparser.NoOptionError as e:
            raise FieldNameError(e)

    def _json_loader(self, conf_path):
        """
        json loader
        :param conf_path:
        :return:
        """
        pass

    def _yaml_loader(self, conf_path):
        """
        yaml loader
        :param conf_path:
        :return:
        """
        pass
